package com.jacky.proxy;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MyProxyTests {
    public static void main(String[] args) throws Exception {
//        新的JDK版本中使用如下语句保存代理类的class文件，保存路径为:工作空间/com/sun/proxy/$Proxy0.class
//        System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");

//        System.out.println("*****************************");
//        mytest1();
//
//        System.out.println("*****************************");
//        ttshow();
//
//        System.out.println("*****************************");
//        jjtest();
//
//        System.out.println("*****************************");
//        mytest();

        System.out.println("*****************************");
        newtest();
    }

    private static void newtest() throws Exception {
        TT instance = new MyHandler().getInstance(new TTImpl());
        // instance 继承了Proxy类，实现了TT接口
        System.out.println("instance实现的类：\t"+instance.getClass().getName());
        System.out.println(instance.getClass().getSimpleName()+"继承的类：\t\t"+instance.getClass().getSuperclass());
        System.out.println(instance.getClass().getSimpleName()+"实现的接口：\t"+instance.getClass().getInterfaces()[0]);
        System.out.println("instance的构造方法：\t"+instance.getClass().getConstructors()[0]);
        System.out.println("instance的方法：");
        for (Method method : instance.getClass().getDeclaredMethods()) {
            System.out.println("\t"+method);
        }
        System.out.println("instance的参数：");
        for (Field field : instance.getClass().getDeclaredFields()) {
            field.setAccessible(true);
            System.out.println("\t"+field+",\tinstance对应的值："+field.get(instance));
        }

        /**
         * instance.show()中调用了 super.h.invoke(this, m3, null);
         * 其中 super代表父类Proxy,h代表父类中的保护属性，
         *      创建代理类$proxy0的实例instance时，
         *      $Proxy0的构造方法通过调用父类Proxy构造方法，
         *      将InvocationHandler接口实例作为参数传递给Proxy的保护属性h，
         *      即Proxy.h=也就是MyHandler的实例
         * 即 super.h.invoke  ==>  Proxy.h.invoke  ==> MyHandler的实例调用invoke方法
         */
        instance.show();
    }


    /**
     * 把Proxy.newProxyInstance()方法放到Handler里
     */
    private static void jjtest() {
        TT object = new TTImpl();
        TT instance = (TT) new MyInvocationHandler().getInstance(object, new Class[] {TT.class});
        instance.show();
    }

    private static void mytest() {
        MyInterface object = new MyImplements();
        MyInterface instance = (MyInterface) new MyInvocationHandler().getInstance(object, new Class[] {MyInterface.class});
        instance.show1();
        instance.show2();
    }

    /**
     * 自己调用Proxy.newProxyInstance()方法
     */
    private static void ttshow() {
//        TT tt = new TTImpl();
//        InvocationHandler invocationHandler = new MyInvocationHandler(tt);
//
//        TT tt1 = (TT) Proxy.newProxyInstance(
//                ClassLoader.getSystemClassLoader(),
//                new Class[] {TT.class},
//                invocationHandler);
//        tt1.show();

        final TTImpl obj = new TTImpl();
        InvocationHandler handler = new MyInvocationHandler(obj);
        final TT o = (TT) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{TT.class}, handler);
        o.show();
    }

    private static void mytest1() {
        MyInterface myInterface = new MyImplements();
        InvocationHandler invocationHandler = new MyInvocationHandler(myInterface);

        MyInterface proxyInstance = (MyInterface) Proxy.newProxyInstance(
//                MyProxyTests.class.getClassLoader(),
                ClassLoader.getSystemClassLoader(),
                new Class[]{MyInterface.class},
                invocationHandler);
        proxyInstance.show1();
        proxyInstance.show2();
    }
}
